在 Linux 中, “一切皆文件” 抽象将所有 I/O 源——从普通文件到网络 套接字——映射为统一的字节流。这种统一接口使得能够以一致的方式进行 系统级 I/O 来管理一个 服务器进程 和 客户端进程 跨 多核处理器。
统一模型
无论程序访问的是 普通文件、 目录还是像 网络适配器这样的硬件,都使用相同的原语。如 硬件架构(图 11.2)所示,操作系统通过 I/O 总线将 CPU 和内存连接到设备,将网络视为文件以简化 多核处理器上的并发。
健壮 I/O 与元数据
为处理 短读写计数 (当请求字节数 $k$ 与可用字节数 $m$ 满足 $k \ge m$ 时), Rio(健壮 I/O)包 提供 rio_readinitb 用于 缓冲输入。元数据通过 stat进行管理,而权限如 O_RDWR 和 S_IROTH 受 umask。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
What is the output of a program that opens 'foo.txt' (getting fd 3), closes it, then opens 'baz.txt'?
$fd2 = 3$
$fd2 = 4$
$fd2 = 0$
Segmentation Fault
✅ Correct!
Linux always assigns the lowest-available file descriptor. Since 3 was freed by Close(), it is reused.❌ Incorrect
Recall the 'Lowest-Available Descriptor Rule'. Once fd 3 is closed, it is the first available slot after 0, 1, and 2.QUESTION 2
If a disk file 'foobar.txt' contains 'foobar' and a process forks after opening it, what is the output if both parent and child read 1 byte?
Both read 'f'
One reads 'f', the other reads 'o'
Both read 'fo'
The child gets an error
✅ Correct!
Because the child inherits the parent's descriptor table, they share the same entry in the Open File Table and thus share the 'Current file position'.❌ Incorrect
A fork() duplicates the descriptor table, but both copies point to the same open file entry in the kernel.QUESTION 3
Which constant represents opening a file for both reading and writing?
O_RDONLY
O_WRONLY
O_RDWR
S_IROTH
✅ Correct!
O_RDWR stands for Open Read/Write.❌ Incorrect
O_RDONLY is read-only; O_WRONLY is write-only. O_RDWR combines both.QUESTION 4
What is a 'Short Count' in the context of Unix I/O?
A file with zero bytes.
When read() or write() transfers fewer bytes than requested.
A limited number of file descriptors.
A CPU clock cycle error.
✅ Correct!
This is common in network sockets where $k \ge m$. The Rio package is used to handle this robustly.❌ Incorrect
Short counts occur when the kernel returns fewer bytes than requested due to EOF or network buffering.QUESTION 5
How does the OS manage the network adapter in the 'Everything is a File' model?
It bypasses the I/O bus entirely.
It maps the adapter to a socket descriptor.
It treats it as a CPU register.
It uses a special network-only language.
✅ Correct!
By treating the network adapter as a file (socket), the system allows standard read/write logic to handle network communication.❌ Incorrect
The hardware organization treats the adapter as an I/O device accessible via file descriptors.Module Case Study: The Robust I/O Redirector
Implementing Redirection and Buffered Reads
A developer is tasked with redirecting the standard input of a process to a log file 'input.log' and then reading the file using the Rio (Robust I/O) package to ensure no data is lost due to short counts on a high-concurrency multi-core system.
Q
1. Which system call would you use to redirect standard input (descriptor 0) to a new file descriptor 'fd'?
Solution:
You would use
You would use
dup2(fd, STDIN_FILENO);. This call atomically closes descriptor 0 (if open) and copies the entry of 'fd' into descriptor 0, effectively redirecting the input stream.Q
2. Why is 'Rio buffered reading' preferred over standard read() when dealing with network sockets?
Solution:
Rio buffered reading (using
Rio buffered reading (using
rio_readinitb and rio_readlineb) reduces system call overhead by copying text lines from an internal buffer. Most importantly, it robustly handles 'short counts' common in network transactions where read() might return before receiving all requested bytes.Q
3. If the process has a umask of 022 and creates a file with S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666), what are the final permissions?
Solution:
The final permissions will be 0644 (
The final permissions will be 0644 (
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH). The umask 022 masks out the write permissions for 'group' and 'others', ensuring the file is not globally writable despite the open() flags.